/*
 *  CSE 40166, Computer Graphics, Fall 2013
 *
 *  PORT
 *  File: texture.cpp
 *
 *  Kevin Sonnen
 *
 *  Description: Contains functions for registering a texture and reading in a PPM.
 *  These functions are very similar to example code given.
 *
 */
 
#include "texture.h"

// registerOpenGLTexture /////////////////////////////////////////////////////////
//
//  This function takes as parameters the raw image data, image dimensions, and
//		the texture handle.  It then creates a texture handle, sets up the texture
//		parameters, and finally registers the texture with OpenGL and the GPU
//
//////////////////////////////////////////////////////////////////////////////////
bool registerOpenGLTexture(unsigned char *textureData, 
						   unsigned int texWidth, unsigned int texHeight, 
						   GLuint &textureHandle) {
    if(textureData == 0) {
        fprintf(stderr,"Cannot register texture; no data specified.");
        return false;
    }
	
	//glGenTextures( 1, &textureHandle );
	glBindTexture( GL_TEXTURE_2D, textureHandle );

	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);	// GL_MODULATE or GL_DECAL
	//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);	// GL_MODULATE or GL_DECAL
	
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  // a MIN Filter MUST BE SET
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	// GL_REPEAT or GL_CLAMP
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		
    GLenum errCode;
    const GLubyte *errString;
	
    if ((errCode = glGetError()) != GL_NO_ERROR) {
        errString = gluErrorString(errCode);
        fprintf(stderr,"Cannot register texture; OpenGL error: %s.", errString);
        return false;
    } 
	
    glTexImage2D( GL_TEXTURE_2D,	// specifying a 2D texture
				 0,					// level of the texture map - used for mipmapping
				 GL_RGB,			// internal format of image data
				 texWidth,			// texture width
				 texHeight,			// texture height
				 0,					// border width - used for filtering
				 GL_RGB,			// type of texels to use
				 GL_UNSIGNED_BYTE,	// how is the data stored in array
				 textureData		// pointer to array of image data
				 );
    return true;
}

// readPPM() ///////////////////////////////////////////////////////////////////
//
//  This function reads an ASCII PPM (P3) or a binary PPM (P6), 
//	returning true if the function succeeds and
//      false if it fails. If it succeeds, the variables imageWidth and 
//      imageHeight will hold the width and height of the read image, respectively.
//
//  It's not terribly robust.
//
//  Returns the image as an unsigned character array containing 
//      imageWidth*imageHeight*3 entries (for that many bytes of storage).
//
//  NOTE: this function expects imageData to be UNALLOCATED, and will allocate 
//      memory itself. If the function fails (returns false), imageData
//      will be set to NULL and any allocated memory will be automatically deallocated.
//
////////////////////////////////////////////////////////////////////////////////
bool readPPM(std::string filename, int &imageWidth, int &imageHeight, unsigned char* &imageData) {
    FILE *fp = fopen(filename.c_str(), "r");
    int temp, maxValue;
    fscanf(fp, "P%d", &temp);
    if (temp == 6) {
	    //got the file header right...
	    fscanf(fp, "%d", &imageWidth);
	    fscanf(fp, "%d", &imageHeight);
	    fscanf(fp, "%d ", &maxValue);
	
	    //now that we know how big it is, allocate the buffer...
	    imageData = new unsigned char[imageWidth*imageHeight*3];
	    if(!imageData) {
		fprintf(stderr, "Error: couldn't allocate image memory. Dimensions: %d x %d.\n", imageWidth, imageHeight);
		fclose(fp);
		return false;
	    }
	
	    fread(imageData,imageWidth*imageHeight*3,sizeof(unsigned char),fp);
    } else if (temp == 3) {
	    //got the file header right...
	    fscanf(fp, "%d", &imageWidth);
	    fscanf(fp, "%d", &imageHeight);
	    fscanf(fp, "%d", &maxValue);
	
	    //now that we know how big it is, allocate the buffer...
	    imageData = new unsigned char[imageWidth*imageHeight*3];
	    if(!imageData) {
		fprintf(stderr, "Error: couldn't allocate image memory. Dimensions: %d x %d.\n", imageWidth, imageHeight);
		fclose(fp);
		return false;
	    }
	
	    //and read the data in.
	    for(int j = 0; j < imageHeight; j++) {
		for(int i = 0; i < imageWidth; i++) {
		    int r, g, b;
		    fscanf(fp, "%d", &r);
		    fscanf(fp, "%d", &g);
		    fscanf(fp, "%d", &b);
			
		    imageData[(j*imageWidth+i)*3+0] = r;
		    imageData[(j*imageWidth+i)*3+1] = g;
		    imageData[(j*imageWidth+i)*3+2] = b;
		}
	    }
    } else {
	fprintf(stderr, "Error: PPM file is not of correct format! (Must be P3 or P6, is P%d.)\n", temp);
        fclose(fp);
        return false;
    }
    
    fclose(fp);
    return true;
}
